---
title: "Notifications"
description: "Handle real-time updates from MCP servers"
icon: "bell"
---

Notifications enable real-time, one-way communication between clients and servers. They're used to signal events, state changes, and updates without requiring a response, making them perfect for keeping your application synchronized with server state.

## Understanding Notifications

MCP notifications are JSON-RPC messages without response requirements. They enable:

- **Real-time updates**: Get notified when server state changes
- **List synchronization**: Tools, resources, and prompts list updates
- **Custom events**: Server-specific notifications for your application
- **Progress tracking**: Monitor long-running operations

<Info>
**Bidirectional**: Both clients and servers can send notifications. Servers notify clients of changes, while clients notify servers of environment changes like root directories.
</Info>

## Notification Flow

**Server → Client**: Event notifications (tool lists changed, progress updates, custom events)

**Client → Server**: Environment notifications (roots changed, configuration updates)

<Tip>
For information on sending notifications from your MCP server, see the [Server Notifications](/typescript/server/notifications) guide.
</Tip>

## Receiving Notifications (Server → Client)

Register a notification handler on your session using the `on` method:

```typescript
import { MCPClient } from "mcp-use";

const client = new MCPClient({
  mcpServers: {
    myServer: { url: "http://localhost:3000/mcp" }
  }
});

const session = await client.createSession("myServer");

// Register notification handler
session.on("notification", async (notification) => {
  console.log(`Received: ${notification.method}`, notification.params);
});
```

## Notification Structure

Notifications follow the JSON-RPC 2.0 format without an `id` field:

```typescript
interface Notification {
  method: string;           // The notification method name
  params?: Record<string, any>;  // Optional parameters
}
```

## Standard MCP Notifications

MCP defines several standard notification types that servers may send:

### Tools List Changed

Sent when the server's available tools have changed:

```typescript
session.on("notification", async (notification) => {
  if (notification.method === "notifications/tools/list_changed") {
    console.log("Tools list updated - refreshing...");
    // Refresh tools cache
    const tools = await session.connector.listTools();
    console.log(`Now have ${tools.length} tools`);
  }
});
```

### Resources List Changed

Sent when resources have been added, removed, or modified:

```typescript
session.on("notification", async (notification) => {
  if (notification.method === "notifications/resources/list_changed") {
    console.log("Resources updated");
    const resources = await session.connector.listAllResources();
    // Update your UI or cache
  }
});
```

### Prompts List Changed

Sent when prompts have changed:

```typescript
session.on("notification", async (notification) => {
  if (notification.method === "notifications/prompts/list_changed") {
    console.log("Prompts updated");
    const prompts = await session.connector.listPrompts();
    // Update your UI or cache
  }
});
```

## Custom Notifications

Servers can send custom notifications with any method name:

```typescript
session.on("notification", async (notification) => {
  switch (notification.method) {
    case "custom/heartbeat":
      console.log(`Heartbeat #${notification.params?.count}`);
      break;
      
    case "custom/user-joined":
      console.log(`User joined: ${notification.params?.username}`);
      break;
      
    case "custom/data-updated":
      console.log("Data updated:", notification.params);
      break;
      
    default:
      console.log(`Unknown notification: ${notification.method}`);
  }
});
```

## Sending Notifications (Client → Server)

### Roots Changed

Roots represent directories or files that the client has access to. When you update roots, the client automatically sends a `notifications/roots/list_changed` notification to the server:

```typescript
import { MCPClient, Root } from "mcp-use";

const client = new MCPClient({
  mcpServers: {
    myServer: { url: "http://localhost:3000/mcp" }
  }
});

const session = await client.createSession("myServer");

// Set roots - this sends notifications/roots/list_changed to the server
await session.setRoots([
  { uri: "file:///home/user/project", name: "My Project" },
  { uri: "file:///home/user/data", name: "Data Directory" }
]);

// Get current roots
const roots = session.getRoots();
console.log(`Current roots: ${roots.length}`);
```

### Initial Roots at Connection

You can provide initial roots when creating the connector:

```typescript
import { HttpConnector } from "mcp-use";

const connector = new HttpConnector("http://localhost:3000/mcp", {
  roots: [
    { uri: "file:///workspace", name: "Workspace" }
  ]
});

const session = new MCPSession(connector);
await session.connect();
await session.initialize();

// Later, update roots
await session.setRoots([
  { uri: "file:///workspace", name: "Workspace" },
  { uri: "file:///tmp/scratch", name: "Scratch" }
]);
```

### Root Type

```typescript
interface Root {
  uri: string;      // Must start with "file://"
  name?: string;    // Optional human-readable name
}
```

## Practical Examples

### Building a Real-Time Dashboard

```typescript
import { MCPClient, Notification } from "mcp-use";

const client = new MCPClient({
  mcpServers: {
    dashboard: { url: "http://localhost:3000/mcp" }
  }
});

const session = await client.createSession("dashboard");

// State
let connectedUsers = 0;
let lastHeartbeat: Date | null = null;

session.on("notification", async (notification: Notification) => {
  switch (notification.method) {
    case "custom/heartbeat":
      lastHeartbeat = new Date();
      connectedUsers = notification.params?.connectedClients ?? 0;
      updateStatusUI();
      break;
      
    case "custom/alert":
      showAlert(notification.params?.message);
      break;
      
    case "notifications/tools/list_changed":
      await refreshToolsList();
      break;
  }
});

function updateStatusUI() {
  console.log(`Status: ${connectedUsers} users, last heartbeat: ${lastHeartbeat}`);
}
```

### Handling Connection Events

```typescript
session.on("notification", async (notification) => {
  if (notification.method === "custom/welcome") {
    console.log("Connected to server!");
    console.log("Server time:", notification.params?.serverTime);
    console.log("Available tools:", notification.params?.availableTools);
  }
});
```

### Progress Updates

```typescript
session.on("notification", async (notification) => {
  if (notification.method === "custom/progress") {
    const { taskId, progress, status } = notification.params ?? {};
    console.log(`Task ${taskId}: ${progress}% - ${status}`);
    
    // Update progress bar UI
    updateProgressBar(taskId, progress);
  }
});
```

## Multiple Handlers

You can register multiple notification handlers:

```typescript
// Handler for logging
session.on("notification", async (notification) => {
  console.log("[LOG]", notification.method, notification.params);
});

// Handler for specific notifications
session.on("notification", async (notification) => {
  if (notification.method === "custom/important") {
    await handleImportantNotification(notification);
  }
});

// Handler for UI updates
session.on("notification", async (notification) => {
  if (notification.method.startsWith("ui/")) {
    updateUI(notification);
  }
});
```

## Error Handling

Errors in notification handlers are caught and logged, but don't stop other handlers:

```typescript
session.on("notification", async (notification) => {
  try {
    // Process notification
    await processNotification(notification);
  } catch (error) {
    console.error("Error processing notification:", error);
    // Handle error - maybe retry or log for debugging
  }
});
```

## Browser Usage

Notifications work the same way in browser environments:

```typescript
import { MCPClient } from "mcp-use/browser";

const client = new MCPClient({
  mcpServers: {
    api: { url: "https://api.example.com/mcp" }
  }
});

const session = await client.createSession("api");

session.on("notification", (notification) => {
  // Update React state, Vue refs, etc.
  setNotifications(prev => [...prev, notification]);
});
```

## TypeScript Types

Import the `Notification` type for type-safe handlers:

```typescript
import { MCPClient, Notification, NotificationHandler } from "mcp-use";

// Type-safe handler
const handler: NotificationHandler = async (notification: Notification) => {
  // notification.method is string
  // notification.params is Record<string, any> | undefined
};

session.on("notification", handler);
```

## Requirements

Notifications require:

1. **Stateful Connection**: The server must maintain sessions (stateful mode)
2. **Active Session**: The client must have an active, initialized session
3. **Streaming Transport**: Either SSE or Streamable HTTP transport

<Note>
Notifications don't work in stateless edge environments where sessions aren't maintained between requests.
</Note>

## Best Practices

1. **Handle Unknown Notifications**: Always have a fallback for notifications you don't recognize
2. **Keep Handlers Fast**: Notification handlers should be quick - offload heavy work
3. **Use TypeScript**: Leverage the `Notification` type for better code quality
4. **Log Notifications**: During development, log all notifications to understand server behavior
5. **Clean Up**: If your session disconnects, handlers won't receive new notifications

## Next Steps

- [Server Notifications](/typescript/server/notifications) - Learn how servers send notifications
- [Connection Types](./connection-types) - Understand transport options
- [Resources](./resources) - Handle resource change notifications
- [Tools](./tools) - Handle tool list change notifications
